﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WowParserLib.Events;

namespace WowParserLib
{
    public class Actor
    {
        private Actor _parent = null;

        private List<Event> _sourceEvents;
        private List<Event> _targetEvents;
        private List<Actor> _children;

        private ulong _id;

        private string _name;

        public Actor(ulong id, string name)
        {
            _id = id;
            _name = name;

            _sourceEvents = new List<Event>();
            _targetEvents = new List<Event>();

            _children = new List<Actor>();
        }

        public ulong Id
        {
            get { return _id; }
        }

        public string Name
        {
            get { return _name; }
        }

        public Actor Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }

        public IEnumerable<Actor> Children
        {
            get 
            {
                return _children;
            }
        }

        public IEnumerable<Event> SourceEvents
        {
            get
            {
                return _sourceEvents;
            }
        }

        public IEnumerable<Event> TargetEvents
        {
            get
            {
                return _targetEvents;
            }
        }

        public void AddChild(Actor child)
        {
            child.Parent = this;
            _children.Add(child);
        }

        public void AddSourceEvent(Event actionEvent)
        {
            if (IsSourceEventValid(actionEvent))
            {
                _sourceEvents.Add(actionEvent);
            }
            else
            {
                throw new ArgumentException(
                    string.Format("Event {0} is not valid for {1}", actionEvent.ToString(), this.GetType().ToString()));
            }
        }

        public void AddTargetEvent(Event actionEvent)
        {
            if (IsTargetEventValid(actionEvent))
            {
                _targetEvents.Add(actionEvent);
            }
            else
            {
                throw new ArgumentException(
                    string.Format("Event {0} is not valid for {1}", actionEvent.ToString(), this.GetType().ToString()));
            }
        }

        protected virtual bool IsSourceEventValid(Event line)
        {
            return (line.Source.Equals(this));
        }

        protected virtual bool IsTargetEventValid(Event targetEvent)
        {
            return (targetEvent.Target.Equals(this));
        }

        public override string ToString()
        {
            return string.Format("{0} => {1}", (Parent!= null) ? _name + "(" + Parent.Name + ")" : _name, _id);
        }

        public override bool Equals(object obj)
        {
            if (obj is Actor)
            {
                Actor actor = obj as Actor;
                return this.Id.Equals(actor.Id);
            }
            return false;
        }

        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        public int GetTotalSwingDamage()
        {
            int damage = 0;
            foreach (Event e in this._sourceEvents)
            {
                if (e is SwingEvent)
                {
                    damage = damage + ((SwingEvent)e).Damage;
                }
            }
            return damage;
        }

        public int GetTotalSpellDamage()
        {
            // linq?
            int damage = 0;
            foreach (Event e in this._sourceEvents)
            {
                if (e is SpellEvent)
                {
                    damage = damage + ((SpellEvent)e).Damage;
                }
            }
            return damage;
        }

        public IEnumerable<Actor> GetTargetActors()
        {
            // itterate through the events finding unique actors and add them to a list
            // then return
            return _sourceEvents.Select(p => p.Target).Distinct();
        }

        public IEnumerable<Event> GetEventsEffectingTarget(Actor target)
        {
            var result = from e in _sourceEvents
                         where e.Target.Equals(target)
                             select e;
            return result;
        }

    }
}
